package net.sf.rose.jdbc.dao;

import java.io.InputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import net.sf.rose.jdbc.ConstantCode;
import net.sf.rose.jdbc.PageBean;
import net.sf.rose.jdbc.bean.FieldBean;
import net.sf.rose.jdbc.bean.TableBean;
import net.sf.rose.jdbc.bean.annotation.Table;
import net.sf.rose.jdbc.query.BeanSQL;
import net.sf.rose.jdbc.query.QuerySQL;
import net.sf.rose.jdbc.service.Service;
import net.sf.rose.util.BeanWrapper;
import net.sf.rose.util.ClassUtils;
import net.sf.rose.util.DataUtils;
import net.sf.rose.util.RoseRuntimeException;

/**
 * 类说明：面向实体类的数据库操作的封装类
 * 
 * @author fengjian
 * @since 2013/05/18
 */
@SuppressWarnings("unchecked")
public class BeanDAO extends GenericDAO {

	private static Logger LOG = Logger.getLogger(BeanDAO.class);

	public BeanDAO() {
		super();
		super.setService(Service.getService());
	}

	public BeanDAO(Service service) {
		super();
		super.setService(service);
	}

	/**
	 * 功能:返回数据库操作SQL语句生成实例
	 * 
	 * @return 数据库操作SQL语句生成实例
	 */
	@Override
	public BeanSQL getQuerySQL() {
		if (super.query == null) {
			BeanSQL q = new BeanSQL();
			q.setService(service);
			super.query = q;
		}
		return (BeanSQL) super.query;
	}

	/**
	 * 功能:从数据库中读取指定的数据类
	 * <p>
	 * 如果查询没有结果，则抛出异常
	 * <p>
	 * 如果查询有多个结果，则抛出异常
	 * 
	 * @param <T> 实体类对象类型
	 * @return 返回取得的数据类
	 */
	@Override
	public <T> T load() {
		try {
			query.prepareSql();
			if (super.isRecordLog()) {
				// 拼写SQL语句日志
				logString = query.getLog().trim();
				LOG.info(logString);
			}
			this.con = service.getConnection();
			this.fillStatement(query.getSql(), query.getParameterList());
			rs = pstmt.executeQuery();
			Object obj = toDataBean(rs, query.getEntityClass());
			if (obj == null) {
				throw new RoseRuntimeException("根据指定的sql语句调用load方法未能找到结果记录！\nsql=" + logString);
			}
			if (rs.next()) {
				throw new RoseRuntimeException("根据指定的sql语句调用load方法能找到结果记录不止一条！\nsql=" + logString);
			}
			return (T) obj;
		} catch (SQLException e) {
			throw ClassUtils.getException("数据库load查询操作失败！sql:" + getLogString(logString), e);
		} catch (Exception e) {
			throw ClassUtils.getException("数据库操作发生未知异常！", e);
		} finally {
			closeResult();
		}
	}

	/**
	 * 功能:从数据库中读取某个值
	 * <p>
	 * 如果查询没有结果，则抛出异常
	 * <p>
	 * 如果查询有多个结果，则抛出异常
	 * 
	 * @param <T> 返回对象类型
	 * @return 返回取得的某个值
	 */
	public <T> T getValue() {
		try {
			query.prepareSql();
			if (super.isRecordLog()) {
				// 拼写SQL语句日志
				logString = query.getLog().trim();
				LOG.info(logString);
			}
			this.con = service.getConnection();
			this.fillStatement(query.getSql(), query.getParameterList());
			rs = pstmt.executeQuery();
			if (!rs.next()) {
				throw new RoseRuntimeException("根据指定的sql语句调用load方法未能找到结果记录！\nsql=" + logString);
			}
			Object obj = rs.getObject(1);
			if (rs.next()) {
				throw new RoseRuntimeException("根据指定的sql语句调用load方法能找到结果记录不止一条！\nsql=" + logString);
			}
			return (T) obj;
		} catch (SQLException e) {
			throw ClassUtils.getException("数据库getValue查询操作失败！sql:" + getLogString(logString), e);
		} catch (Exception e) {
			throw ClassUtils.getException("数据库操作发生未知异常！", e);
		} finally {
			closeResult();
		}
	}

	/**
	 * 功能:从数据库中读取指定的数据类
	 * <p>
	 * 如果查询没有结果，则返回null
	 * <p>
	 * 如果查询有多个结果，则返回第一条记录
	 * 
	 * @param <T> 实体类对象类型
	 * @return 返回取得的数据类
	 */
	@Override
	public <T> T get() {
		try {
			query.prepareSql();
			if (super.isRecordLog()) {
				// 拼写SQL语句日志
				logString = query.getLog().trim();
				LOG.info(logString);
			}
			this.con = service.getConnection();
			this.fillStatement(query.getSql(), query.getParameterList());
			rs = pstmt.executeQuery();
			Object obj = toDataBean(rs, query.getEntityClass());
			return obj == null ? null : (T) obj;
		} catch (SQLException e) {
			throw ClassUtils.getException("数据库get查询操作失败！sql:" + getLogString(logString), e);
		} catch (Exception e) {
			throw ClassUtils.getException("数据库操作发生未知异常！", e);
		} finally {
			closeResult();
		}
	}

	/**
	 * 功能:通过SQL取得数据类列表
	 * 
	 * @param <T> 实体类对象类型
	 * @return 结果列表
	 */
	@Override
	public <T> List<T> list() {
		// 执行SQL语句
		try {
			TableBean table = Service.getTableBean(query.getTableName());
			query.prepareSql();
			this.con = service.getConnection();
			// 如果排序有内容，把排序加上
			if (query.getOrderBy().size() > 0) {
				StringBuilder sb = new StringBuilder();
				sb.append(" ORDER BY ");
				for (String[] arr : query.getOrderBy()) {
					FieldBean field = table.getFieldBeanByPropertyName(arr[0]);
					if (field == null) {
						throw new RoseRuntimeException("根据属性名称" + arr[0] + "没有找到实体类的字段...");
					}
					sb.append(field.getFieldName());
					if (arr.length == 2 && arr[1] != null) {
						sb.append(' ').append(arr[1]).append(',');
					} else {
						sb.append(',');
					}
				}
				query.addSql(sb.substring(0, sb.length() - 1));
			}
			// 如果需要分页
			if (query.getPage() != null) {
				PageBean page = query.getPage();
				// 如果不是oracle
				if (!service.getDatabaseType().equals("oracle")) {
					logString = query.getCountSql();
					this.fillStatement(logString, query.getParameterList());
					rs = pstmt.executeQuery();
					if (rs.next()) {
						long count = rs.getLong(1);
						if (count != 0) {
							// 保存符合条件的记录数量
							page.setTotal(Integer.parseInt(count + ""));
						}
					}
				} else {
					page.setOraclePageSQL(query);
				}
			}
			if (super.isRecordLog()) {
				// 拼写SQL语句日志
				logString = query.getLog().trim();
				LOG.info(logString);
			}
			this.fillStatement(query.getSql(), query.getParameterList());
			rs = pstmt.executeQuery();
			List<Object> list = toDataListBean(rs, query);
			// 清空分页组件
			query.setPage(null);
			return (List<T>) list;
		} catch (SQLException e) {
			throw ClassUtils.getException("数据库list查询操作失败！sql:" + getLogString(logString), e);
		} catch (Exception e) {
			e.printStackTrace();
			throw ClassUtils.getException("数据库操作发生未知异常！", e);
		} finally {
			closeResult();
		}
	}

	/**
	 * 功能:将数据库查询结果集中的数据列表加载入DataBean类，并封装至ArrayList类中。
	 * 
	 * @param rs - ResultSet结果集
	 * @return List<DataBean>数据列表
	 * @throws Exception - 如果操作失败将抛出异常
	 */
	private List<Object> toDataListBean(ResultSet rs, QuerySQL query) throws Exception {
		if (!rs.next()) {
			List<Object> list = new java.util.ArrayList<>();
			PageBean page = query.getPage();
			if (page != null) {
				page.setData(list);
			}
			return list;
		}
		Class<?> entityClass = query.getEntityClass();
		String[] colNames = getColNames(rs);
		TableBean table = Service.getTableBean(query.getTableName());
		Map<String, FieldBean> map = table.getFieldNameFieldMap();
		// 如果父类也是数据库映射实体类
		Class<?> parent = entityClass.getSuperclass();
		while (!parent.getName().equals("java.lang.Object")) {
			Table t = parent.getAnnotation(Table.class);
			if (t != null && !t.name().equals("")) {
				TableBean b = Service.getTableBean(t.name());
				Map<String, FieldBean> m = new HashMap<>();
				m.putAll(map);
				m.putAll(b.getFieldNameFieldMap());
				map = m;
				parent = parent.getSuperclass();
			} else {
				break;
			}
		}
		int columnCount = colNames.length;
		// 判断此次查询需要分页，且当前使用的数据库是Oracle
		int needGetOracleDataCount = -1;
		PageBean page = query.getPage();
		if (page != null && service.getDatabaseType().equals("oracle")) {
			// 值为0表示需要取Oracle查询的总记录数
			needGetOracleDataCount = 0;
			columnCount = columnCount - 2;
		}
		rs.last(); // 移到最后一行
		int size = rs.getRow(); // 得到当前行号，也就是记录数
		rs.beforeFirst(); // 把指针再移到初始化的位置
		Object t;
		// String key = null;
		Object val = null;
		List<Object> list = new java.util.ArrayList<>(size);
		BeanWrapper bw = new BeanWrapper();
		// 获取当前操作的用户对象
		Object user = super.service.getUser();
		if (user != null) {
			if (!(user instanceof String)) {
				// 如果当前用户对象存在，且设置了个性化语言
				bw.setWrappedInstance(user);
				Object language = bw.get("language");
				if (language != null) {
					bw.setLanguage(language.toString());
				}
				bw.setWrappedClass(entityClass);
			}
		}
		while (rs.next()) {
			if (needGetOracleDataCount == 0) {
				// 取Oracle查询的总记录数
				if (page.getTotal() < 1) {
					needGetOracleDataCount = Integer.parseInt(rs.getObject(columnCount + 2).toString());
					page.setTotal(needGetOracleDataCount);
				}
			}
			t = entityClass.newInstance();
			bw.setWrappedInstance(t);
			for (int i = 1; i <= columnCount; i++) {
				val = null;
				FieldBean field = map.get(colNames[i - 1]);
				if (field != null) {
					// 如果是流文件
					if (field.getJavaType().equals(ConstantCode.JAVA_TYPE_INPUTSTREAM)) {
						InputStream in = rs.getBinaryStream(i);
						if (in != null) {
							val = DataUtils.inputStreamToByte(in);
						}
					} else {
						val = rs.getObject(i);
					}
					if (val != null) {
						bw.set(field.getPropertyName(), val);
					}
				}
			}
			list.add(t);
		}
		// 如果需要分页，将结果数据集装入分页类中
		if (page != null) {
			page.setData(list);
		}
		return list;
	}

	/**
	 * 功能:将数据库查询结果集中的数据加载入DataBean类中。
	 * 
	 * @param rs - ResultSet结果集
	 * @return DataBean数据类
	 * @throws Exception - 如果操作失败将抛出异常
	 */
	private Object toDataBean(ResultSet rs, Class<?> entityClass) throws Exception {
		if (!rs.next()) {
			return null;
		}
		// String key = null;
		Object val = null;
		String[] colNames = getColNames(rs);
		TableBean table = Service.getTableBean(query.getTableName());
		Map<String, FieldBean> map = table.getFieldNameFieldMap();
		// 如果父类也是数据库映射实体类
		Class<?> parent = entityClass.getSuperclass();
		while (!parent.getName().equals("java.lang.Object")) {
			Table t = parent.getAnnotation(Table.class);
			if (t != null && !t.name().equals("")) {
				TableBean b = Service.getTableBean(t.name());
				Map<String, FieldBean> m = new HashMap<>();
				m.putAll(map);
				m.putAll(b.getFieldNameFieldMap());
				map = m;
				parent = parent.getSuperclass();
			} else {
				break;
			}
		}
		Object t = entityClass.newInstance();
		BeanWrapper bw = new BeanWrapper();
		// 获取当前操作的用户对象
		Object user = super.service.getUser();
		if (user != null) {
			if (!(user instanceof String)) {
				// 如果当前用户对象存在，且设置了个性化语言
				bw.setWrappedInstance(user);
				Object language = bw.get("language");
				if (language != null) {
					bw.setLanguage(language.toString());
				}
				bw.setWrappedClass(entityClass);
			}
		}
		bw.setWrappedInstance(t);
		for (int i = 1; i <= colNames.length; i++) {
			val = null;
			FieldBean field = map.get(colNames[i - 1]);
			if (field != null) {
				// 如果是流文件
				if (field.getType().equals(ConstantCode.DATA_TYPE_STREAM)) {
					InputStream in = rs.getBinaryStream(i);
					if (in != null) {
						val = DataUtils.inputStreamToByte(in);
					}
				} else {
					val = rs.getObject(i);
				}
				if (val != null) {
					bw.set(field.getPropertyName(), val);
				}
			}
		}
		return t;
	}

}
